home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / emac16as.arc / SEARCH.ASM < prev    next >
Assembly Source File  |  1990-04-01  |  26KB  |  1,174 lines

  1. ;History:772,1
  2. ;Wed Nov 29 23:58:27 1989 Add support for \|
  3. ;Tue Nov 07 23:45:44 1989 match newlines in character classes.
  4. ;Mon Nov 06 00:40:16 1989 try to make backwards regexp searches work.
  5. ;Sat Nov 05 22:05:14 1988 let CR LF match LINENEW.
  6. ;10-08-88 08:48:54 add \n to regexp search.
  7. ;09-26-88 21:23:42 add case translation for character classes.
  8. ;08-19-88 23:36:40 closure didn't work because omatch iterated on matching.
  9. ;08-13-88 22:12:46 try forwards again.
  10. ;07-24-88 16:42:24 BOL and EOL match BOB and EOB respectively.
  11. ;07-21-88 22:49:18 add optimized search backwards.
  12. ;07-20-88 00:15:38 too late at night to continue...
  13. ;07-20-88 00:02:35 optimize forward searches.
  14. ;07-19-88 23:38:07 use the right omatch_chr for both regexps and literals.
  15. ;07-19-88 00:51:06 initialize the case table.
  16. ;07-18-88 21:20:18 don't increment di twice in omatch_NCCL
  17. ;07-18-88 00:04:34 replace bad patterns with "".
  18. ;07-17-88 23:15:23 Check for topbot right after incrementing di.
  19. ;07-17-88 22:55:12 search *at* the end_ptr (check for end_ptr after searching).
  20. ;07-17-88 18:54:53 when searching backwards, don't search past right_ptr.
  21. ;07-17-88 10:59:27 save di around omatch()
  22. ;07-17-88 10:42:13 omatch_CHR was incrementing di even if it didn't match.
  23. ;06-06-88 23:58:09 change the regexp chars to match Gnu's.
  24. ;07-06-87 06:55:31 Use botbot for eof, not LINENEW
  25.     include    memory.def
  26.  
  27. data    segment    byte public
  28.  
  29. b_struc    struc
  30. b    db    ?
  31. b_struc    ends
  32.  
  33. w_struc    struc
  34. w    dw    ?
  35. w_struc    ends
  36.  
  37.     extrn    outpat: byte
  38.     extrn    OUTPATSIZE: abs
  39. inpat_ptr    dw    ?        ;beginning of input pattern.
  40. direction    dw    ?        ;routine to increment di in correct direction.
  41. scan_char    dw    ?        ;routine to scan for a character.
  42. end_ptr        dw    ?        ;end of region we're searching.
  43. right_ptr    dw    ?        ;rightmost end of region we're searching.
  44. clo_si        dw    ?        ;saved pointer for closure.
  45. last_ptr    dw    ?        ;pointer to last character matched.
  46. which_chr    dw    ?        ;which omatch_CHR to use.
  47. this_pattern    dw    ?        ;->this pattern (for closure).
  48. last_pattern    dw    ?        ;->previous pattern (for closure).
  49. last_or        dw    ?        ;->last or pointer.
  50.  
  51.     extrn    textseg: word
  52.  
  53. init_case        dw    init_case_table
  54. case_ignore_table    db    256 dup(?)
  55.  
  56. data    ends
  57.  
  58.  
  59. bufseg    segment    public
  60.  
  61.     extrn    toptop: word
  62.     extrn    topbot: word
  63.     extrn    bottop: word
  64.     extrn    botbot: word
  65.  
  66. bufseg    ends
  67.  
  68.  
  69. code    segment    byte public
  70.     assume    cs:code, ds:data, ss:data
  71.  
  72.     public    slowly
  73.  
  74.     extrn    get_mark: near, set_mark_si: near
  75.     extrn    get_syntax: near
  76.  
  77.     public    search
  78. search:
  79. ;enter with ch=start mark, cl=end mark, dh=first mark, dl=last mark.
  80. ;start searching at mark ch.  If the string is found, then return the
  81. ;  beginning in mark dh, and the end in mark dl, and cy=0.  If the string
  82. ;  wasn't found, return cy=1.
  83.     push    dx            ;save the first, last marks.
  84.     push    es
  85.     mov    es,textseg
  86.     assume    es:bufseg
  87.     push    ds            ;save ds
  88.     push    es
  89.     pop    ds
  90.     assume    ds:bufseg        ;for get_mark
  91.     mov    al,cl            ;get the end mark.
  92.     push    cx
  93.     call    get_mark
  94.     mov    end_ptr,si        ;save a copy of the end.
  95.     mov    right_ptr,si        ;save a copy of the end.
  96.     pop    cx
  97.     mov    al,ch            ;get the start mark.
  98.     call    get_mark
  99.     pop    ds            ;restore ds
  100.     assume    ds:data
  101.     mov    direction,offset inc_di
  102.     cmp    si,end_ptr        ;start>=end?
  103.     jb    search_4        ;no.  (doesn't matter if they're equal)
  104.     mov    direction,offset dec_di    ;yes, go in reverse direction.
  105.     mov    right_ptr,si        ;yes, remember that start is rightmost.
  106. search_4:
  107.     mov    di,si            ;get the pointer to our string.
  108.     call    slowly
  109.     pop    es
  110.     assume    es:data
  111.     pop    dx
  112.     jc    search_1        ;not found.
  113.  
  114.     push    ds
  115.     mov    ds,textseg        ;for set_mark_si
  116.     assume    ds:bufseg
  117.     mov    al,dh
  118.     mov    si,di
  119.     call    set_mark_si        ;set the first mark.
  120.  
  121.     mov    si,last_ptr
  122.     mov    al,dl
  123.     call    set_mark_si        ;set the last mark.
  124.  
  125.     pop    ds
  126.     assume    ds:data
  127.     clc                ;return a match.
  128.     ret
  129. search_1:
  130.     stc                ;return no match.
  131.     ret
  132.  
  133.  
  134.     assume    ds:data, es:bufseg
  135.  
  136.  
  137. scan_char_literal:
  138.     or    sp,sp            ;ensure NZ in case cx=0.
  139.     repne    scasb            ;search for the character.
  140.     ret
  141.  
  142.  
  143. scan_char_fold:
  144.     xlat
  145.     mov    ah,al
  146.     or    sp,sp            ;if cx=0, be sure to return nz.
  147.     jcxz    scan_char_fold_2
  148.     shr    cx,1            ;we unrolled the loop once.
  149.     jnc    scan_char_fold_1    ;if even, start at the top.
  150.     inc    cx            ;otherwise, add one for the odd
  151.     jmp    short scan_char_fold_3    ;  iteration, and jump to it.
  152. scan_char_fold_1:
  153.     mov    al,es:[di]        ;unroll this puppy once.
  154.     add    di,dx
  155.     xlat
  156.     cmp    al,ah            ;compare them.
  157.     je    scan_char_fold_2    ;if equal, we're done.
  158. scan_char_fold_3:
  159.     mov    al,es:[di]        ;now do the second set.
  160.     add    di,dx
  161.     xlat
  162.     cmp    al,ah
  163.     loopne    scan_char_fold_1
  164. scan_char_fold_2:
  165.     mov    al,ah            ;get our character back.
  166.     ret
  167.  
  168.  
  169. slowly:
  170. ;es:si -> first char to look at.
  171. ;es:right_ptr -> after last char to look at.
  172. ;return cy if no match,
  173. ;  else nc, si->start of match, last_ptr->after end of match.
  174.     cmp    di,topbot        ;at topbot already?
  175.     jne    slowly_0
  176.     mov    di,bottop
  177. slowly_0:
  178.     mov    ax,which_chr        ;does the pattern start with a CHR?
  179.     cmp    ax,word ptr outpat
  180.     jne    slowly_1        ;no.
  181.     cmp    outpat+2,CR        ;searching for literal CR?
  182.     je    slowly_1        ;yes - don't optimize because of CRLFs.
  183.     cmp    outpat+2,LF        ;searching for literal LF?
  184.     je    slowly_1        ;yes - don't optimize because of CRLFs.
  185.  
  186.     mov    scan_char,offset scan_char_literal
  187.     cmp    ax,offset omatch_CHR    ;Are we folding case?
  188.     je    quickly_1        ;no.
  189.     mov    scan_char,offset scan_char_fold
  190. quickly_1:
  191.     cmp    direction,offset inc_di    ;Are we going forwards?
  192.     je    forwards_0        ;yes.
  193.   if 0 ;disable optimization for now.
  194.     jmp    slowly_1
  195.   endif
  196.     jmp    backwards_0        ;no.
  197.  
  198. slowly_1:
  199.     mov    si,offset outpat    ;start at beginning of pattern.
  200.     mov    bx,offset case_ignore_table
  201.     push    di            ;remember where we're starting.
  202.     call    omatch            ;now search.
  203.     pop    di
  204.     jnc    slowly_succeed        ;we found a match
  205. ;not found, should we give up?
  206.     cmp    di,end_ptr        ;at the end yet?
  207.     je    slowly_fail        ;yes - not found.
  208. ;not found, we have to bump di.
  209.     call    direction
  210.     jmp    slowly_1
  211. slowly_fail:
  212.     stc                ;not found.
  213.     ret
  214. slowly_succeed:
  215.   if 1    ;an attempt to make backwards regexp searches work right.
  216.     cmp    direction,offset inc_di    ;Are we going forwards?
  217.     je    slowly_done        ;yes - we're done now.
  218. slowly_backwards_again:
  219.     call    dec_di            ;move backwards.
  220.     push    last_ptr        ;remember the pointer to the end of it.
  221.     mov    si,offset outpat    ;start at beginning of pattern.
  222.     mov    bx,offset case_ignore_table
  223.     push    di
  224.     call    omatch            ;did it match?
  225.     pop    di
  226.     pop    ax
  227.     jc    slowly_backwards_done    ;no - we're done.
  228.     cmp    ax,last_ptr        ;did last_ptr change?
  229.     je    slowly_backwards_again    ;no, we can try again.
  230. slowly_backwards_done:
  231.     mov    last_ptr,ax
  232.     call    inc_di            ;point to the last match again.
  233. slowly_done:
  234.   endif
  235.     clc
  236.     ret
  237.  
  238.     public    forwards_0
  239. forwards_0:
  240.     mov    bx,offset case_ignore_table
  241.     mov    al,outpat+2        ;get the character
  242.     cmp    di,bottop        ;are we in the bottom?
  243.     jae    forwards_2        ;yes - don't search the top.
  244.  
  245.     mov    cx,topbot        ;should we search to topbot
  246.     cmp    cx,end_ptr        ;  or to end_ptr?
  247.     jbe    forwards_3
  248.     mov    cx,end_ptr        ;just to end_ptr.
  249. forwards_3:
  250.     sub    cx,di            ;compute the amount left in the top.
  251.     mov    dx,1
  252.     call    scan_char        ;scan for our character.
  253.     je    forwards_1        ;we found it!
  254.  
  255.     cmp    di,end_ptr        ;are we at the end?
  256.     jae    slowly_fail        ;yes - no match.
  257.  
  258.     mov    di,bottop
  259. forwards_2:
  260.     mov    cx,end_ptr        ;we only need search that far.
  261.     sub    cx,di
  262.     mov    dx,1
  263.     call    scan_char        ;scan for our character.
  264.     jne    slowly_fail        ;we didn't find it.
  265. forwards_1:
  266.     mov    si,offset outpat+3    ;start at beginning of pattern.
  267.     push    di            ;remember where we're starting.
  268.     call    omatch            ;now search.
  269.     pop    di
  270.     jnc    forwards_4        ;we matched - return it.
  271.     cmp    di,end_ptr        ;are we at the end?
  272.     jb    forwards_0        ;no - keep matching.
  273. slowly_fail_j_1:
  274.     jmp    slowly_fail        ;yes - no match.
  275. forwards_4:
  276.     dec    di            ;remember that we actually started
  277.     jmp    slowly_succeed        ;  one character into the pattern.
  278.  
  279.  
  280.     public    backwards_0
  281. backwards_0:
  282.     mov    bx,offset case_ignore_table
  283.     mov    al,outpat+2        ;get the character
  284.     cmp    di,bottop        ;are we in the top?
  285.     jb    backwards_2        ;yes - don't search the bottom.
  286.     je    backwards_5
  287.  
  288.     mov    si,bottop        ;should we search to bottop
  289.     cmp    si,end_ptr        ;  or to end_ptr?
  290.     jae    backwards_3
  291.     mov    si,end_ptr        ;just to end_ptr.
  292. backwards_3:
  293.  
  294.     dec    di
  295.     mov    cx,di            ;compute the amount left in the bottom.
  296.     sub    cx,si
  297.     inc    cx            ;be sure to look at where di points.
  298.     std
  299.     mov    dx,-1
  300.     call    scan_char        ;scan for our character.
  301.     cld
  302.     je    backwards_1        ;we found it!
  303.  
  304. backwards_5:
  305.     cmp    di,end_ptr        ;are we at the end?
  306.     jbe    slowly_fail_j_1        ;yes - no match.
  307.  
  308.     mov    di,topbot
  309.     dec    di
  310. backwards_2:
  311.     mov    cx,di            ;we only search here if end_ptr is here.
  312.     sub    cx,end_ptr
  313.     inc    cx            ;be sure to compare where di is.
  314.     std
  315.     mov    dx,-1
  316.     call    scan_char        ;scan for our character.
  317.     cld
  318.     jne    slowly_fail_j_1        ;we didn't find it.
  319. backwards_1:
  320.     mov    si,offset outpat+3    ;start at beginning of pattern.
  321.     push    di            ;remember where we're starting.
  322.     add    di,2            ;we post-decremented.
  323.     call    omatch            ;now search.
  324.     pop    di
  325.     jnc    backwards_4        ;we suceeded.
  326.     inc    di
  327.     cmp    di,end_ptr        ;are we after the end?
  328.     jb    slowly_fail_j_1        ;yes - no match.
  329.     dec    di
  330.     jmp    backwards_0
  331. backwards_4:
  332.     inc    di            ;remember that we post-decremented,
  333.     jmp    slowly_succeed        ;  so we're one character too far.
  334.  
  335. inc_di:
  336. ;bump di forwards.
  337.     inc    di
  338.     cmp    di,topbot        ;at bottom of top?
  339.     je    inc_di_1        ;yes - can't possibly be split over newline.
  340.     cmp    es:[di-1].w,LINENEW    ;did we just move into a newline?
  341.     jne    inc_di_2        ;no.
  342.     inc    di            ;yes - skip LF part of newline.
  343.     cmp    di,topbot        ;at topbot already?
  344.     jne    inc_di_2
  345. inc_di_1:
  346.     mov    di,bottop
  347. inc_di_2:
  348.     ret
  349.  
  350. dec_di:
  351. ;bump di backwards.
  352.     cmp    di,bottop        ;at top of bottom?
  353.     jne    dec_di_1        ;no.
  354.     mov    di,topbot        ;yes - load bottom of top.
  355. dec_di_1:
  356.     dec    di            ;back up to previous character.
  357.     cmp    es:[di-1].w,LINENEW    ;at newline?
  358.     jne    dec_di_2        ;no.
  359.     cmp    di,bottop        ;at top of bottom now?
  360.     je    dec_di_2        ;yes - can't possibly be split over newline.
  361.     dec    di            ;yes - skip to beginning of newline.
  362. dec_di_2:
  363.     ret
  364.  
  365.  
  366. omatch:
  367. ;return nc if we matched, cy if not.
  368. ;es:di -> source text
  369. ;ds:si -> pattern
  370. omatch_0:
  371.     cmp    di,topbot        ;at bottom of top?
  372.     jne    omatch_1
  373.     mov    di,bottop        ;yes, go to top of bottom.
  374. omatch_1:
  375.     lodsw
  376.     call    ax
  377.     jnc    omatch_0
  378.     ret
  379.  
  380.  
  381. ;each of the omatch_XXX routines operates under the following constraints
  382. ;  on failure, return with cy set.
  383. ;  on matching (only used by omatch_EOS right now), return to caller's caller
  384. ;    with cy clear.
  385. ;  on success, bump si as needed so that it points to the next omatch,
  386. ;    bump di as needed (either zero or one), and return with cy clear.
  387.  
  388.     public    omatch_EOS
  389. omatch_EOS:
  390.     mov    last_ptr,di        ;remember the last thing we matched.
  391.     add    sp,2            ;pop our return address.
  392.     clc                ;if we get to the end of the
  393.     ret                ;  pattern, then we matched.
  394.  
  395.     public    omatch_CLO
  396. omatch_CLO:
  397.     push    di            ;save the first closure pattern.
  398.     mov    CLO_si,si        ;remember the pattern we're closing.
  399. ;Note that we don't have to worry about CLO_si being global because the
  400. ;  next pattern can't be another closure.
  401. ;match as many as fit the next pattern
  402.     mov    bx,offset case_ignore_table
  403. omatch_CLO_1:
  404.     mov    si,CLO_si        ;get the pattern being closed.
  405.     cmp    di,topbot        ;at bottom of top?
  406.     jne    omatch_CLO_5
  407.     mov    di,bottop        ;yes, go to top of bottom.
  408. omatch_CLO_5:
  409.     lodsw
  410.     call    ax
  411.     jnc    omatch_CLO_1
  412.     pop    bx
  413. ;match only as many as fit the pattern after the next pattern.
  414. omatch_CLO_2:
  415.     push    si
  416.     push    di
  417.     push    bx
  418.     mov    bx,offset case_ignore_table
  419.     call    omatch            ;try to match rest of pattern.
  420.     pop    bx
  421.     pop    di
  422.     pop    si
  423.     jnc    omatch_CLO_4        ;go if it matched.
  424.     cmp    di,bottop        ;backing up past the point?
  425.     jne    omatch_CLO_3        ;no - just decrement.
  426.     mov    di,topbot        ;yes - get the bottom of the top.
  427. omatch_CLO_3:
  428.     dec    di            ;point to the previous character.
  429.     cmp    di,bx            ;zero or more matches still?
  430.     jae    omatch_CLO_2        ;yes.
  431.     stc                ;no matches--return no match.
  432.     ret
  433. omatch_CLO_4:
  434.     pop    bx            ;get rid of our return address.
  435.     ret
  436.  
  437.  
  438. omatch_OR:
  439.     add    si,2            ;skip past our param.
  440.     push    si
  441.     push    di
  442.     mov    bx,offset case_ignore_table
  443.     call    omatch            ;try to match rest of pattern.
  444.     jnc    omatch_OR_1        ;go if it matched.
  445.     pop    di
  446.     pop    si
  447.     push    si
  448.     mov    si,[si-2]        ;point to the next or-clause.
  449.     push    di
  450.     call    omatch
  451.     jnc    omatch_OR_1        ;go if it matched.
  452.     pop    di
  453.     pop    si
  454. ;guaranteed cy.
  455.     ret
  456. omatch_OR_1:
  457.     add    sp,6            ;get rid of si,di, and our return addr.
  458. ;guaranteed nc.
  459.     ret
  460.  
  461.  
  462.     public    omatch_CHR
  463. omatch_CHR:
  464.     cmp    di,right_ptr        ;are we at the end?
  465.     je    omatch_CHR_skip        ;yes - we never match CHR
  466.     cmp    es:[di].w,LINENEW
  467.     je    omatch_CHR_linenew
  468.     cmpsb
  469.     je    omatch_yes        ;if they're the same, match again.
  470.     dec    di            ;don't modify buffer pointer if no match.
  471.     stc
  472.     ret
  473. omatch_CHR_linenew:
  474.     cmp    [si].b,CR        ;got a LINENEW, are we looking for one?
  475.     jne    omatch_CHR_skip        ;no.
  476.     mov    ax,which_chr        ;is the next one another char?
  477.     cmp    [si+1].w,ax
  478.     jne    omatch_CHR_skip        ;no - no match.
  479.     cmp    [si+1+2].b,LF        ;Are we really looking for a linenew?
  480.     jne    omatch_CHR_skip        ;no - no match.
  481.     add    si,1+2+1        ;skip past the two of them.
  482.     add    di,2            ;skip in the buffer also.
  483.     clc
  484.     ret
  485. omatch_CHR_skip:
  486.     inc    si            ;skip the pattern character.
  487. omatch_CHR_no:
  488.     stc
  489.     ret
  490. omatch_yes:
  491.     clc
  492.     ret
  493.  
  494.  
  495.     public    omatch_NCHR
  496. omatch_NCHR:
  497.     cmp    di,right_ptr        ;are we at the end?
  498.     je    omatch_CHR_skip        ;yes - we never match CHR
  499.     cmp    es:[di].w,LINENEW
  500.     je    omatch_CHR_linenew
  501.     lodsb
  502.     xlat
  503.     mov    ah,al
  504.     mov    al,es:[di]
  505.     inc    di
  506.     xlat
  507.     cmp    ah,al
  508.     je    omatch_yes        ;if they're the same, match again.
  509.     dec    di            ;don't modify buffer pointer if no match.
  510.     stc
  511.     ret
  512.  
  513.  
  514. omatch_NL:
  515.     cmp    di,right_ptr        ;are we at the end?
  516.     je    omatch_NL_no        ;yes - we never match newline.
  517.     cmp    es:[di].w,LINENEW    ;is it newline?
  518.     jne    omatch_NL_no        ;no - don't match it.
  519.     add    di,2            ;yes - skip it.
  520.     clc
  521.     ret
  522. omatch_NL_no:
  523.     stc
  524.     ret
  525.  
  526.  
  527.     public    omatch_BOB
  528. omatch_BOB:
  529. ;match beginning of buffer.
  530.     cmp    di,toptop        ;are we at the beginning of the buffer?
  531.     je    omatch_yes        ;yes.
  532.     stc
  533.     ret
  534.  
  535.  
  536.     public    omatch_BOL
  537. omatch_BOL:
  538. ;match beginning of line.
  539.     push    di            ;we might have to look at the top.
  540.     cmp    di,bottop        ;are we at the point?
  541.     jne    omatch_BOL_1        ;yes - ok.
  542.     mov    di,topbot        ;no - get the top.
  543. omatch_BOL_1:
  544.     cmp    di,toptop
  545.     je    omatch_BOL_2
  546.     cmp    es:[di-2].w,LINENEW
  547.     pop    di
  548.     jne    omatch_CHR_no
  549.     clc
  550.     ret
  551. omatch_BOL_2:
  552.     pop    di
  553.     clc
  554.     ret
  555.  
  556.  
  557.     public    omatch_ISW
  558. omatch_ISW:
  559. ;match word character.
  560.     cmp    di,botbot
  561.     je    omatch_CHR_no
  562.     cmp    es:[di].w,LINENEW
  563.     je    omatch_CHR_no
  564.     call    chars_around_di
  565.     test    al,1            ;word character?
  566.     je    omatch_CHR_no        ;nope--no match.
  567.     inc    di            ;match the character.
  568.     clc
  569.     ret
  570.  
  571.  
  572.     public    omatch_NOW
  573. omatch_NOW:
  574. ;match word character.
  575.     cmp    di,botbot
  576.     je    omatch_no
  577.     cmp    es:[di].w,LINENEW
  578.     je    omatch_no
  579.     call    chars_around_di
  580.     test    al,1            ;whitespace before and word after?
  581.     jne    omatch_no        ;nope--no match.
  582.     inc    di            ;match the character.
  583.     clc
  584.     ret
  585.  
  586.  
  587.     public    omatch_BOW
  588. omatch_BOW:
  589. ;match beginning of word.
  590.     cmp    di,botbot
  591.     je    omatch_no
  592.     cmp    es:[di].w,LINENEW
  593.     je    omatch_no
  594.     call    chars_around_di
  595.     cmp    al,1            ;whitespace before and word after?
  596.     jne    omatch_no        ;nope--no match.
  597.     clc
  598.     ret
  599.  
  600.  
  601.     public    omatch_EOW
  602. omatch_EOW:
  603. ;match end of word.
  604.     call    chars_around_di
  605.     cmp    al,2            ;word before and whitespace after?
  606.     jne    omatch_no        ;nope--no match.
  607.     clc
  608.     ret
  609.  
  610.  
  611.     public    omatch_WOR
  612. omatch_WOR:
  613. ;match end of word.
  614.     call    chars_around_di
  615.     cmp    al,2            ;word before and whitespace after?
  616.     je    omatch_WOR_yes        ;yes - match.
  617.     cmp    al,1            ;whitespace before and word after?
  618.     je    omatch_WOR_yes        ;yes - match.
  619.     stc
  620.     ret
  621. omatch_WOR_yes:
  622.     clc
  623.     ret
  624.  
  625.  
  626.     public    omatch_NWR
  627. omatch_NWR:
  628. ;match end of word.
  629.     call    chars_around_di
  630.     cmp    al,0            ;whitespace before and whitespace after?
  631.     je    omatch_NWR_yes        ;yes - match.
  632.     cmp    al,3            ;word before and word after?
  633.     je    omatch_NWR_yes        ;yes - match.
  634.     stc
  635.     ret
  636. omatch_NWR_yes:
  637.     clc
  638.     ret
  639.  
  640.  
  641.     public    omatch_EOB
  642. omatch_EOB:
  643. ;match end of buffer.
  644.     cmp    di,botbot        ;are we at the end of the buffer?
  645.     je    omatch_NWR_yes        ;yes.
  646.     stc
  647.     ret
  648.  
  649.  
  650.     public    omatch_EOL
  651. omatch_EOL:
  652. ;match end of line.
  653.     cmp    di,botbot        ;are we at the end?
  654.     je    omatch_EOL_yes        ;yes.
  655.     cmp    es:[di].w,LINENEW
  656.     jne    omatch_no
  657. omatch_EOL_yes:
  658.     clc
  659.     ret
  660. omatch_no:
  661.     stc
  662.     ret
  663.  
  664.  
  665.     public    omatch_ANY
  666. omatch_ANY:
  667. ;match any single character.
  668.     cmp    di,right_ptr        ;are we at the end?
  669.     je    omatch_no        ;yes - we never match ANY
  670.     cmp    es:[di].w,LINENEW    ;we never match EOL.
  671.     je    omatch_no
  672.     inc    di
  673.     clc
  674.     ret
  675.  
  676.  
  677.     public    omatch_CCL
  678. omatch_CCL:
  679. ;match a character class.
  680.     cmp    di,right_ptr        ;are we at the end?
  681.     je    omatch_ccl_no        ;yes - we never match CCL
  682.     cmp    es:[di].w,LINENEW    ;we never match EOL.
  683.     je    omatch_ccl_newline
  684.     call    locate            ;see if it's in our set.
  685.     jnz    omatch_no        ;nope.
  686.     inc    di
  687.     clc
  688.     ret
  689. omatch_ccl_newline:
  690.     lea    ax,[di+1]        ;are we near the end?
  691.     cmp    ax,right_ptr
  692.     je    omatch_ccl_no        ;yes - no match.
  693.     cmp    ds:[si+1].w,LINENEW    ;does the class begin with crlf?
  694.     jne    omatch_ccl_no        ;no - don't match it.
  695.     lodsb                ;skip past this pattern.
  696.     xor    ah,ah
  697.     add    si,ax
  698.     add    di,2
  699.     clc
  700.     ret
  701.  
  702.  
  703.     public    omatch_NCCL
  704. omatch_NCCL:
  705. ;match not in a character class.
  706.     cmp    di,right_ptr        ;are we at the end?
  707.     je    omatch_ccl_no        ;yes - we never match NCCL
  708.     cmp    es:[di].w,LINENEW    ;we only match EOL if it begins the class.
  709.     je    omatch_ccl_no
  710.     call    locate            ;see if it's in our set.
  711.     jz    omatch_ccl_no        ;yes - we don't match.
  712.     inc    di
  713.     clc
  714.     ret
  715. omatch_ccl_no:
  716.     lodsb                ;skip past the pattern.
  717.     xor    ah,ah
  718.     add    si,ax
  719.     stc
  720.     ret
  721.  
  722.  
  723. locate:
  724. ;es:di -> search string, bx -> case translate table.
  725. ;ds:si -> CCL
  726. ;exit with zr if found, nz if not found, si -> after the pattern.
  727.     push    cx
  728.     lodsb                ;get the count.
  729.     mov    cl,al
  730.     xor    ch,ch
  731.     mov    al,es:[di]        ;get the character we're trying to match.
  732.     xlat                ;case translate it.
  733.     mov    ah,al            ;keep it somewhere safe.
  734. locate_2:
  735.     lodsb
  736.     xlat
  737.     cmp    al,ah            ;is this one it?
  738.     loopne    locate_2
  739.     lahf                ;remember whether or not we found it.
  740.     add    si,cx
  741.     sahf
  742.     pop    cx
  743.     ret
  744.  
  745.  
  746. chars_around_di:
  747. ;return al bit 1=syntax of char to left of point.
  748. ;    al bit 0=syntax of char to right of point.
  749.     push    di            ;get the character before point.
  750.     cmp    di,bottop        ;are we at the point?
  751.     jne    chars_around_di_1    ;yes.
  752.     mov    di,topbot
  753. chars_around_di_1:
  754.     xor    al,al            ;if no character, it's whitespace.
  755.     cmp    di,toptop
  756.     je    chars_around_di_2
  757.     mov    al,es:[di-1]
  758.     call    get_syntax        ;get the syntax for the char before point.
  759.     and    al,1            ;isolate the 'word' bit.
  760. chars_around_di_2:
  761.     shl    al,1
  762.     mov    ah,al
  763.     pop    di
  764.  
  765.     xor    al,al            ;if no character, it's whitespace.
  766.     cmp    di,botbot        ;are we at the end?
  767.     je    chars_around_di_3    ;yes - can't match beginning of word.
  768.     mov    al,es:[di]
  769.     call    get_syntax
  770.     and    al,1
  771. chars_around_di_3:
  772.     or    al,ah            ;include the syntax of the char to left of point.
  773.     ret
  774.  
  775.  
  776.     assume    ds:data
  777.  
  778.     public    set_pattern
  779. set_pattern:
  780. ;enter with si, cx->pattern.  dx<>0 if regular expression.  di <> 0 if we
  781. ;  want to fold case.
  782. ;exit with cy=1 if error.
  783.     call    init_case
  784.     mov    ax,offset omatch_CHR
  785.     or    di,di
  786.     je    set_pattern_0
  787.     mov    ax,offset omatch_NCHR
  788. set_pattern_0:
  789.     mov    which_chr,ax        ;remember which omatch_CHR to use.
  790.     or    dx,dx
  791.     jne    regexp_pat
  792.     mov    di,offset outpat
  793.     jcxz    set_pattern_1
  794.     mov    bp,offset outpat-2
  795.     add    bp,OUTPATSIZE
  796. set_pattern_2:
  797.     cmp    di,bp            ;do we have enough room?
  798.     jae    set_pattern_3        ;no - quit now.
  799.     stosw                ;store the appropriate comparison omatcher.
  800.     movsb
  801.     loop    set_pattern_2
  802. set_pattern_1:
  803.     mov    ax,offset omatch_EOS    ;store the end of string.
  804.     stosw
  805.     clc
  806.     ret
  807. set_pattern_3:
  808.     stc
  809.     ret
  810.  
  811.  
  812.     public    regexp_pat
  813. regexp_pat:
  814. ;enter with si, cx->pattern.
  815. ;exit with cy=1 if error.
  816.     mov    bx,cx
  817.     mov    [si+bx],byte ptr 0    ;store the terminating null.
  818.     call    makepat
  819.     jnc    regexp_pat_1
  820.     mov    word ptr outpat,offset omatch_EOS    ;uh-oh, bad pattern -- null it.
  821. regexp_pat_1:
  822.     ret
  823.  
  824.  
  825. makepat:
  826. ;si -> source pat (null terminated)
  827. ;di -> dest pattern, dx -> last dest entry.
  828. ;bx -> last closure
  829. ;return cy=1 if error.
  830.     mov    inpat_ptr,si
  831.     mov    di,offset outpat
  832.     mov    dx,OUTPATSIZE
  833.     add    dx,di
  834.     mov    last_pattern,-1        ;remember where the previous pattern started.
  835.     mov    last_or,di        ;remember that it's here.
  836. makepat_1:
  837.     lodsb                ;get the first character.
  838.     or    al,al            ;end of string?
  839.     je    makepat_0        ;yes.
  840.  
  841.     mov    this_pattern,di        ;remember where this pattern starts.
  842.  
  843.     cmp    al,'\'            ;are we escaping something?
  844.     jne    makepat_a
  845.     cmp    byte ptr [si],0        ;is the '\' at the end?
  846.     je    makepat_9        ;yes - just use \.
  847.     lodsb                ;get the escaped char.
  848.     call    escaped_char        ;check for the special escapes.
  849.     jmp    makepat_2
  850. makepat_a:
  851.     cmp    al,'.'
  852.     jne    makepat_3
  853.     mov    ax,offset omatch_ANY
  854.     call    addset
  855.     jmp    makepat_2
  856. ;this really belongs at the end of makepat, but the short jump can't get there.
  857. makepat_0:
  858.     mov    ax,offset omatch_EOS
  859.     call    addset
  860.     cmp    di,dx
  861.     jne    makepat__0_1
  862.     stc
  863.     ret
  864. makepat__0_1:
  865.     clc
  866.     ret
  867. makepat_3:
  868.     cmp    al,'^'
  869.     jne    makepat_7
  870.     lea    ax,[si-1]        ;get the buffer pointer.
  871.     cmp    ax,inpat_ptr        ;are we at the beginning?
  872.     jne    makepat_6        ;no - this can't be it.
  873.     mov    ax,offset omatch_BOL
  874.     call    addset
  875.     jmp    makepat_2
  876. makepat_6:
  877.     mov    al,'^'
  878.     call    addchar
  879.     jmp    makepat_2
  880. makepat_7:
  881.     cmp    al,'$'
  882.     jne    makepat_8
  883.     cmp    word ptr [si],'\' + '|'*256;is the '$' at the end of an alternation?
  884.     je    makepat_7a        ;no - not special.
  885.     cmp    byte ptr [si],0        ;is the '$' at the end?
  886.     jne    makepat_9        ;no - not special.
  887. makepat_7a:
  888.     mov    ax,offset omatch_EOL
  889.     call    addset
  890.     jmp    makepat_2
  891. makepat_9:
  892.     call    addchar
  893.     jmp    makepat_2
  894. makepat_8:
  895.     cmp    al,'['
  896.     jne    makepat_10
  897.     call    getccl
  898.     jnc    makepat_2
  899.     pop    di
  900.     stc
  901.     ret
  902. makepat_10:
  903.     cmp    al,'*'
  904.     jne    makepat_11
  905.     cmp    last_pattern,0        ;is last_pattern>0?
  906.     jnge    makepat_12        ;no - not closure.
  907.     mov    bx,last_pattern
  908.     mov    ax,word ptr [bx]
  909.     cmp    ax,offset omatch_CLO    ;trying to close a closure?
  910.     je    makepat_12        ;yes - not closure.
  911.     cmp    ax,offset omatch_BOL    ;trying to close a beginning of line?
  912.     je    makepat_12        ;yes - not closure.
  913.     call    stclos
  914.     mov    this_pattern,bx        ;remember where this one was.
  915.     jmp    makepat_2
  916. makepat_11:
  917. ;put more characters here.
  918. makepat_12:
  919.     call    addchar
  920.     jmp    makepat_2
  921. makepat_2:
  922.     mov    bx,this_pattern
  923.     mov    last_pattern,bx
  924.     jmp    makepat_1
  925.  
  926.  
  927. escaped_char:
  928.     mov    cx,offset omatch_NL
  929.     cmp    al,"n"            ;newline?
  930.     je    escaped_1
  931.  
  932.     mov    cx,offset omatch_BOB
  933.     cmp    al,"`"            ;beginning of buffer?
  934.     je    escaped_1
  935.  
  936.     mov    cx,offset omatch_EOB
  937.     cmp    al,"'"            ;end of buffer?
  938.     je    escaped_1
  939.  
  940.     mov    cx,offset omatch_WOR
  941.     cmp    al,"b"            ;beginning or end of word?
  942.     je    escaped_1
  943.  
  944.     mov    cx,offset omatch_NWR
  945.     cmp    al,"B"            ;not beginning nor end of word?
  946.     je    escaped_1
  947.  
  948.     mov    cx,offset omatch_BOW
  949.     cmp    al,"<"            ;beginning of word?
  950.     je    escaped_1
  951.  
  952.     mov    cx,offset omatch_EOW
  953.     cmp    al,">"            ;end of word?
  954.     je    escaped_1
  955.  
  956.     mov    cx,offset omatch_ISW
  957.     cmp    al,"w"            ;word character?
  958.     je    escaped_1
  959.  
  960.     mov    cx,offset omatch_NOW
  961.     cmp    al,"W"            ;not word character?
  962.     je    escaped_1
  963.  
  964.     cmp    al,'|'            ;is this an "or" operator?
  965.     jne    addchar            ;no.
  966.  
  967.     mov    inpat_ptr,si        ;start a new regexp here...
  968.     call    stor            ;store a "or" operator.
  969.     ret
  970. escaped_1:
  971.     mov    ax,cx
  972.     call    addset
  973.     ret
  974.  
  975. addchar:
  976. ;al = CHR to put.
  977.     push    ax
  978.     mov    ax,which_chr        ;use the right omatch_chr.
  979.     call    addset
  980.     pop    ax
  981.     call    addbyte
  982.     ret
  983.  
  984.  
  985. addset:            ;only command chars call addset.
  986.     call    addbyte
  987.     xchg    ah,al
  988.     call    addbyte
  989.     xchg    ah,al
  990.     ret
  991.  
  992.  
  993. addbyte:
  994. ;al = char to put, di->dest, dx->end of dest.
  995.     cmp    di,dx
  996.     je    addbyte_1
  997.     mov    [di],al
  998.     inc    di
  999. addbyte_1:
  1000.     ret
  1001.  
  1002.  
  1003. stclos:
  1004. ;di->last set added + 1
  1005. ;bx->last closure added
  1006.     push    di
  1007. stclos_1:
  1008.     dec    di
  1009.     mov    al,[di]
  1010.     mov    [di+2],al
  1011.     cmp    di,bx
  1012.     jne    stclos_1
  1013. stclos_2:
  1014.     mov    word ptr [bx],offset omatch_CLO
  1015.     pop    di
  1016.     add    di,2
  1017.     ret
  1018.  
  1019.  
  1020. stor:
  1021. ;di->last set added + 1
  1022.     mov    bx,last_or
  1023.     push    di
  1024. stor_1:
  1025.     dec    di
  1026.     mov    al,[di]
  1027.     mov    [di+4],al
  1028.     cmp    di,bx
  1029.     jne    stor_1
  1030. stor_2:
  1031.     pop    di            ;get the new last set.
  1032.     add    di,4
  1033.     mov    ax,offset omatch_EOS    ;store the end of string.
  1034.     stosw
  1035.     mov    word ptr [bx],offset omatch_OR
  1036.     mov    [bx+2],di        ;remember where the next starts.
  1037.     mov    last_or,bx
  1038.     ret
  1039.  
  1040.  
  1041. getccl:
  1042. ;si -> source (null terminated)
  1043. ;di -> dest, dx -> end of dest
  1044. ;return cy=1 if error.
  1045.     lodsb
  1046.     cmp    al,'^'
  1047.     jne    getccl_1
  1048.     mov    ax,offset omatch_NCCL
  1049.     call    addset
  1050.     jmp    getccl_2
  1051. getccl_1:
  1052.     dec    si            ;unparse the '^'.
  1053.     mov    ax,offset omatch_CCL
  1054.     call    addset
  1055. getccl_2:
  1056.     push    bx
  1057.     mov    bx,di
  1058.     call    addbyte            ;leave room for count
  1059.     call    dodash
  1060.     mov    ax,di
  1061.     sub    ax,bx
  1062.     dec    al
  1063.     mov    [bx],al
  1064.     pop    bx
  1065.     lodsb
  1066.     cmp    al,']'            ;now make sure that we end in ']'.
  1067.     je    getccl_3        ;yup, we do.
  1068.     dec    si            ;make si -> the null.
  1069.     stc
  1070.     ret
  1071. getccl_3:
  1072.     clc
  1073.     ret
  1074.  
  1075.  
  1076. dodash:
  1077. ;si -> source pattern (null terminated)
  1078. ;di -> destination pattern
  1079. ;dx -> end of destination pattern
  1080.     push    bx
  1081.     mov    bx,si
  1082. dodash_1:
  1083.     lodsb
  1084.     or    al,al
  1085.     je    dodash_2
  1086.     cmp    al,']'
  1087.     je    dodash_2
  1088.     cmp    al,'-'
  1089.     je    dodash_4
  1090.     call    addbyte
  1091.     jmp    dodash_1
  1092. dodash_4:
  1093.     cmp    si,bx            ;'-' at beginning?
  1094.     je    dodash_5
  1095.     cmp    [si].b,0        ;or '-' at end?
  1096.     jne    dodash_6
  1097. dodash_5:
  1098.     mov    al,'-'            ;if at beginning or at end, just a '-'
  1099.     call    addbyte
  1100.     jmp    dodash_1
  1101. dodash_6:
  1102.     mov    al,[si-2]        ;in increasing alphabetic order?
  1103.     cmp    al,[si]
  1104.     ja    dodash_5        ;no - forget it.
  1105.     call    alphanumeric        ;left char alphanumeric?
  1106.     jnc    dodash_5        ;no - forget it.
  1107.     mov    al,[si]
  1108.     call    alphanumeric        ;right char alphanumeric?
  1109.     jnc    dodash_5        ;no - forget it.
  1110.     mov    al,[si-2]
  1111. dodash_7:
  1112.     inc    al            ;pre-increment -- the first one's there.
  1113.     cmp    al,[si]
  1114.     ja    dodash_9
  1115.     call    addbyte
  1116.     jmp    dodash_7
  1117. dodash_9:
  1118.     inc    si
  1119.     jmp    dodash_1
  1120. dodash_2:
  1121.     dec    si
  1122.     pop    bx
  1123.     ret
  1124.  
  1125.  
  1126. alphanumeric:
  1127. ;return cy=1 if al is alphanumeric
  1128.     cmp    al,'0'
  1129.     jb    alphanumeric_1
  1130.     cmp    al,'9'
  1131.     jbe    alphanumeric_2
  1132.     cmp    al,'A'
  1133.     jb    alphanumeric_1
  1134.     cmp    al,'Z'
  1135.     jbe    alphanumeric_2
  1136.     cmp    al,'a'
  1137.     jb    alphanumeric_1
  1138.     cmp    al,'z'
  1139.     jbe    alphanumeric_2
  1140. alphanumeric_1:
  1141.     clc
  1142.     ret
  1143. alphanumeric_2:
  1144.     stc
  1145.     ret
  1146.  
  1147.  
  1148. init_case_table:
  1149.     push    bx
  1150.     mov    init_case,offset init_case_2
  1151.     mov    bx,0
  1152. init_case_0:
  1153.     mov    case_ignore_table[bx],bl
  1154.     inc    bl
  1155.     jne    init_case_0
  1156. ;now translate 'a' to 'A'.
  1157.     mov    bx,'a'
  1158. init_case_1:
  1159.     mov    al,bl
  1160.     sub    al,20h
  1161.     mov    case_ignore_table[bx],al
  1162.     inc    bx
  1163.     cmp    bx,'z'
  1164.     jbe    init_case_1
  1165.     pop    bx
  1166. init_case_2:
  1167.     ret
  1168.  
  1169.  
  1170. code    ends
  1171.  
  1172.     end
  1173.  
  1174.